import type { CustomRequestOptions } from '@/interceptors/request'
import type { ApiRes } from '@/types/global'
import { useAuthStore } from '@/store'
import { goLoginPage } from '@/utils/page'

// 自定义请求配置类型
interface HttpConfig {
  /** 响应数据中代表状态码的字段名 */
  codeField: string
  /** 响应数据中代表消息的字段名 */
  msgField: string
  /** 响应数据中代表数据的字段名 */
  dataField: string
  /** 响应数据中代表请求是否成功的字段名 */
  successField: string
  /** 表示请求成功的状态码（业务状态码） */
  successCodes: (string | number)[]
  /** 错误消息处理函数 */
  makeErrorMessage?: (message: string, error: any) => void
  /** 是否直接返回 data 字段，默认为 true */
  returnData?: boolean
  /** 是否校验请求响应码，默认为 true */
  checkCode?: boolean
}

// 默认配置
const defaultConfig: HttpConfig = {
  codeField: 'code',
  msgField: 'msg',
  dataField: 'data',
  successField: 'success',
  successCodes: ['0'],
  makeErrorMessage: undefined,
  returnData: false,
  checkCode: true,
}

// 获取错误信息的函数
function getErrorMessage(code: string | number, customMsg?: string): string {
  const codeStr = String(code)

  // 错误码映射
  switch (codeStr) {
    case '400':
      return customMsg || '请求参数错误'
    case '401':
      return '登录已过期，请重新登录'
    case '403':
      return '您没有权限访问该资源'
    case '404':
      return '请求的资源不存在'
    case '408':
      return '请求超时，请稍后重试'
    case '500':
    case '501':
    case '502':
    case '503':
    case '504':
      return '服务器错误，请稍后重试'
    default:
      // 如果有自定义消息，优先使用自定义消息
      return customMsg || `未知错误(${code})`
  }
}

// 处理错误并显示提示
function handleError(
  code: string | number,
  customMsg: string | undefined,
  hideToast: boolean | undefined,
  defaultMsg = '未知错误',
  options?: {
    // 自定义处理特定错误码的行为
    handlers?: Record<string, () => void>
    // 自定义Toast配置
    toastOptions?: Partial<UniApp.ShowToastOptions>
    // 错误消息处理函数
    makeErrorMessage?: (message: string, error: any) => void
  },
): string {
  const codeStr = String(code)
  // 获取错误信息
  const errorMsg = customMsg ? getErrorMessage(code, customMsg) : getErrorMessage(code) || `${defaultMsg}(${code})`

  // 如果提供了自定义错误消息处理函数，则调用
  if (options?.makeErrorMessage) {
    options.makeErrorMessage(errorMsg, { code, message: customMsg })
  }

  // 显示错误提示（如果没有自定义错误处理函数或显式要求隐藏toast）
  if (!hideToast && !options?.makeErrorMessage) {
    uni.showToast({
      icon: 'none',
      duration: 2000,
      ...options?.toastOptions,
      title: errorMsg,
    })
  }

  // 处理特定错误码的特殊逻辑
  if (options?.handlers && options.handlers[codeStr]) {
    // 如果提供了针对该错误码的自定义处理函数，则调用
    options.handlers[codeStr]()
  }
  else if (codeStr === '401') {
    // 默认处理401未授权的情况
    const authStore = useAuthStore()
    authStore.reset()
    goLoginPage()
  }

  return errorMsg
}

// 扩展自定义请求选项
type ExtendedRequestOptions = CustomRequestOptions & {
  /** 自定义响应返回类型 */
  responseReturn?: 'raw' | 'body'
  /** 是否直接返回 data 字段，覆盖全局配置 */
  returnData?: boolean
  /** 是否校验请求响应码，覆盖全局配置 */
  checkCode?: boolean
}

/**
 * 创建HTTP请求客户端
 * @returns HTTP请求函数
 * @param customConfig
 */
export function createHttp(customConfig?: Partial<HttpConfig>) {
  // 合并默认配置和自定义配置
  const config = { ...defaultConfig, ...customConfig }

  // 核心请求函数
  function request<T>(options: ExtendedRequestOptions) {
    // 返回 Promise 对象
    return new Promise<ApiRes<T>>((resolve, reject) => {
      uni.request({
        ...options,
        dataType: 'json',
        // #ifndef MP-WEIXIN
        responseType: 'json',
        // #endif
        // 响应成功
        success(res) {
          // 获取状态码和响应数据
          const { statusCode } = res
          const responseData = res.data as ApiRes<T>

          // 状态码 2xx，参考 axios 的设计
          if (statusCode >= 200 && statusCode < 300) {
            // 如果需要返回原始响应
            if (options.responseReturn === 'raw') {
              resolve(responseData)
              return
            }

            // 检查是否需要校验响应码
            const shouldCheckCode = options.checkCode !== undefined ? options.checkCode : config.checkCode

            if (!shouldCheckCode) {
              // 不校验响应码，直接返回数据
              const shouldReturnData = options.returnData !== undefined ? options.returnData : config.returnData
              if (shouldReturnData) {
                resolve(responseData[config.dataField] as ApiRes<T>)
              }
              else {
                resolve(responseData)
              }
              return
            }

            // 检查业务状态码是否成功
            const businessCode = responseData[config.codeField]
            const isBusinessSuccess
              = responseData[config.successField] === true
              || config.successCodes.includes(businessCode)

            if (isBusinessSuccess) {
              // 业务成功
              // 根据配置决定是否直接返回 data 字段
              const shouldReturnData = options.returnData !== undefined ? options.returnData : config.returnData
              if (shouldReturnData) {
                resolve(responseData[config.dataField] as ApiRes<T>)
              }
              else {
                resolve(responseData)
              }
            }
            else {
              // 业务失败，根据业务状态码处理不同的错误情况
              const errorMsg = handleError(
                businessCode,
                responseData[config.msgField],
                options.hideErrorToast,
                '业务处理失败',
                { makeErrorMessage: config.makeErrorMessage },
              )
              reject(new Error(errorMsg))
            }
          }
          else {
            // HTTP 错误状态码
            const errorMsg = handleError(
              statusCode,
              responseData[config.msgField],
              options.hideErrorToast,
              '请求错误',
              { makeErrorMessage: config.makeErrorMessage },
            )
            reject(new Error(errorMsg))
          }
        },
        // 响应失败
        fail(_err) {
          // 网络错误或请求被中断
          try {
            const errorMsg = handleError(
              -1, // 网络错误码统一用 -1 表示
              '网络异常，请检查网络连接',
              options.hideErrorToast,
              '网络连接异常',
              {
                toastOptions: { duration: 3000 },
                makeErrorMessage: config.makeErrorMessage,
              },
            )
            reject(new Error(errorMsg))
          }
          catch (e) {
            // 确保错误被处理
            console.error('请求失败:', e)
            reject(new Error('网络异常，请检查网络连接'))
          }
        },
      })
    })
  }

  /**
   * GET 请求
   * @param url 后台地址
   * @param query 请求query参数
   * @param options
   * @returns Promise对象
   */
  function get<T>(url: string, query?: Record<string, any>, options?: Partial<ExtendedRequestOptions>) {
    return request<T>({
      url,
      query,
      method: 'GET',
      ...options,
    })
  }

  /**
   * POST 请求
   * @param url 后台地址
   * @param data 请求body参数
   * @param query 请求query参数
   * @param options
   * @returns Promise对象
   */
  function post<T>(url: string, data?: Record<string, any>, query?: Record<string, any>, options?: Partial<ExtendedRequestOptions>) {
    return request<T>({
      url,
      query,
      data,
      method: 'POST',
      ...options,
    })
  }

  /**
   * PUT 请求
   * @param url 后台地址
   * @param data 请求body参数
   * @param query 请求query参数
   * @param options
   * @returns Promise对象
   */
  function put<T>(url: string, data?: Record<string, any>, query?: Record<string, any>, options?: Partial<ExtendedRequestOptions>) {
    return request<T>({
      url,
      query,
      data,
      method: 'PUT',
      ...options,
    })
  }

  /**
   * DELETE 请求
   * @param url 后台地址
   * @param query 请求query参数
   * @param options
   * @returns Promise对象
   */
  function del<T>(url: string, query?: Record<string, any>, options?: Partial<ExtendedRequestOptions>) {
    return request<T>({
      url,
      query,
      method: 'DELETE',
      ...options,
    })
  }

  /**
   * PATCH 请求
   * @param url 后台地址
   * @param data 请求body参数
   * @param query 请求query参数
   * @param options
   * @returns Promise对象
   */
  function patch<T>(url: string, data?: Record<string, any>, query?: Record<string, any>, options?: Partial<ExtendedRequestOptions>) {
    return request<T>({
      url,
      query,
      data,
      method: 'POST',
      header: {
        'X-HTTP-Method-Override': 'PATCH',
        ...options?.header,
      },
      ...options,
    })
  }

  // 添加请求方法别名
  request.get = get
  request.post = post
  request.put = put
  request.delete = del
  request.patch = patch

  return request
}

// 创建默认HTTP客户端
export const http = createHttp()

// 导出默认请求方法的别名，方便直接使用
export const httpGet = http.get
export const httpPost = http.post
export const httpPut = http.put
export const httpDelete = http.delete
export const httpPatch = http.patch

export default { http, httpGet, httpPost, httpPut, httpDelete, httpPatch }
